package gu.simplemq.pool;

import java.lang.reflect.Constructor;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

import com.google.common.base.Throwables;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;

import gu.simplemq.exceptions.SmqRuntimeException;

/**
 * 线程安全的消息组件实例管理类
 * @author guyadong
 *
 * @param <R> 消息组件组件类型
 * @param <P> 连接线程池类型
 */
public abstract class  BaseMQInstance<R,P>{
	/** 保存每个 P对应的 R 实例 */
	private final LoadingCache<P, R> cache = 
			CacheBuilder.newBuilder()
			.build(new CacheLoader<P,R>(){
				@Override
				public R load(P key) throws Exception {
					constructor.setAccessible(true);
					return constructor.newInstance(key);
				}});
	/** R 的构造函数 */
	private final Constructor<R> constructor;
	/**
	 * usage:<pre>new BaseMQInstance&lt;Model,Pool&gt;(){};</pre>
	 */
	@SuppressWarnings("unchecked")
	protected BaseMQInstance() {
		try {
			Type superClass = getClass().getGenericSuperclass();
			Class<R> rClass = (Class<R>) ((ParameterizedType) superClass).getActualTypeArguments()[0];
			Class<P> pClass = (Class<P>) ((ParameterizedType) superClass).getActualTypeArguments()[1];
			constructor = rClass.getDeclaredConstructor(pClass);
		} catch (Throwable e) {
			throw new SmqRuntimeException(e);
		}
	}
	protected void beforeDelete(R r){}
	/** 删除{@link #instances}中所有实例,
	 * 如果实例实现了{@link AutoCloseable}接口则执行close方法 */
	public synchronized void  clearInstances(){
			for(R r:cache.asMap().values()){
				beforeDelete(r);
				try {
					if(r instanceof AutoCloseable){
						((AutoCloseable)r).close();
					}
				} catch (Throwable e) {
					Throwables.throwIfUnchecked(e);
					throw new RuntimeException(e);
				}
			}
			cache.asMap().clear();
	}
	/**
	 * 返回 {@link #instances}中 P 对应的R实例, 如果没有找到就创建一个新实例加入。
	 * @param pool
	 * @return R instance
	 */
	public R getInstance(P pool){
		return cache.getUnchecked(pool);			
	}
}